home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / code / wire.lisp < prev   
Encoding:
Text File  |  1992-05-30  |  20.7 KB  |  669 lines

  1. ;;; -*- Log: code.log; Package: wire -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: wire.lisp,v 1.9 92/05/15 17:51:43 wlott Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;; This file contains an interface to internet domain sockets.
  15. ;;;
  16. ;;; Written by William Lott.
  17. ;;;
  18.  
  19. (in-package "WIRE")
  20.  
  21. (export '(remote-object-p remote-object
  22.       remote-object-local-p remote-object-eq
  23.       remote-object-value make-remote-object forget-remote-translation
  24.       make-wire wire-p wire-fd wire-listen wire-get-byte wire-get-number
  25.       wire-get-string wire-get-object wire-force-output wire-output-byte
  26.       wire-output-number wire-output-string wire-output-object
  27.       wire-output-funcall wire-error wire-eof wire-io-error
  28.       *current-wire* wire-get-bignum wire-output-bignum))
  29.  
  30.  
  31. (eval-when (compile load eval) ;For macros in remote.lisp.
  32.  
  33. (defconstant buffer-size 2048)
  34.  
  35. (defconstant initial-cache-size 16)
  36.  
  37. (defconstant funcall0-op 0)
  38. (defconstant funcall1-op 1)
  39. (defconstant funcall2-op 2)
  40. (defconstant funcall3-op 3)
  41. (defconstant funcall4-op 4)
  42. (defconstant funcall5-op 5)
  43. (defconstant funcall-op 6)
  44. (defconstant number-op 7)
  45. (defconstant string-op 8)
  46. (defconstant symbol-op 9)
  47. (defconstant save-op 10)
  48. (defconstant lookup-op 11)
  49. (defconstant remote-op 12)
  50. (defconstant cons-op 13)
  51. (defconstant bignum-op 14)
  52.  
  53. ) ;eval-when
  54.  
  55.  
  56. (defvar *current-wire* nil
  57.   "The wire the form we are currently evaluating came across.")
  58.  
  59. (defvar *this-host* nil
  60.   "Unique identifier for this host.")
  61. (defvar *this-pid* nil
  62.   "Unique identifier for this process.")
  63.  
  64. (defvar *object-to-id* (make-hash-table :test 'eq)
  65.   "Hash table mapping local objects to the corresponding remote id.")
  66. (defvar *id-to-object* (make-hash-table :test 'eql)
  67.   "Hash table mapping remote id's to the curresponding local object.")
  68. (defvar *next-id* 0
  69.   "Next available id for remote objects.")
  70.  
  71.  
  72. (defstruct (wire
  73.             (:constructor make-wire (fd))
  74.             (:print-function
  75.              (lambda (wire stream depth)
  76.                (declare (ignore depth))
  77.                (format stream
  78.                        "#<wire fd=~a>"
  79.                (wire-fd wire)))))
  80.   fd
  81.  
  82.   (ibuf (make-string buffer-size))
  83.   (ibuf-offset 0)
  84.   (ibuf-end 0)
  85.   (object-cache (make-array initial-cache-size))
  86.  
  87.   (obuf (make-string buffer-size))
  88.   (obuf-end 0)
  89.   (cache-index 0)
  90.   (object-hash (make-hash-table :test 'eq)))
  91.  
  92. (defstruct (remote-object
  93.         (:constructor %make-remote-object (host pid id))
  94.         (:print-function
  95.          (lambda (obj stream depth)
  96.            (declare (ignore depth))
  97.            (format stream "#<Remote Object: [~x:~a] ~s>"
  98.                (remote-object-host obj)
  99.                (remote-object-pid obj)
  100.                (remote-object-id obj)))))
  101.   host
  102.   pid
  103.   id)
  104.  
  105. (define-condition wire-error (error)
  106.   (wire)
  107.   (:report (lambda (condition stream)
  108.          (format stream "There is a problem with ~A."
  109.              (wire-error-wire condition)))))
  110.  
  111. (define-condition wire-eof (wire-error)
  112.   ()
  113.   (:report (lambda (condition stream)
  114.          (format stream "Recieved EOF on ~A."
  115.              (wire-eof-wire condition)))))
  116.  
  117. (define-condition wire-io-error (wire-error)
  118.   ((when :init-form "using")
  119.    (msg :init-form "Failed."))
  120.   (:report (lambda (condition stream)
  121.          (format stream "Error ~A ~A: ~A."
  122.              (wire-io-error-when condition)
  123.              (wire-io-error-wire condition)
  124.              (wire-io-error-msg condition)))))
  125.  
  126.  
  127. ;;; Remote Object Randomness
  128.  
  129. ;;; REMOTE-OBJECT-LOCAL-P -- public
  130. ;;;
  131. ;;;   First, make sure the *this-host* and *this-pid* are set. Then test to
  132. ;;; see if the remote object's host and pid fields are *this-host* and
  133. ;;; *this-pid*
  134.  
  135. (defun remote-object-local-p (remote)
  136.   "Returns T iff the given remote object is defined locally."
  137.   (declare (type remote-object remote))
  138.   (unless *this-host*
  139.     (setf *this-host* (unix:unix-gethostid))
  140.     (setf *this-pid* (unix:unix-getpid)))
  141.   (and (eql (remote-object-host remote) *this-host*)
  142.        (eql (remote-object-pid remote) *this-pid*)))
  143.  
  144. ;;; REMOTE-OBJECT-EQ -- public
  145. ;;;
  146. ;;;   Remote objects are considered EQ if they refer to the same object, ie
  147. ;;; Their host, pid, and id fields are the same (eql, cause they are all
  148. ;;; numbers).
  149.  
  150. (defun remote-object-eq (remote1 remote2)
  151.   "Returns T iff the two objects refer to the same (eq) object in the same
  152.   process."
  153.   (declare (type remote-object remote1 remote2))
  154.   (and (eql (remote-object-host remote1)
  155.         (remote-object-host remote2))
  156.        (eql (remote-object-pid remote1)
  157.         (remote-object-pid remote2))
  158.        (eql (remote-object-id remote1)
  159.         (remote-object-id remote2))))
  160.  
  161. ;;; REMOTE-OBJECT-VALUE --- public
  162. ;;;
  163. ;;;   First assure that the remote object is defined locally. If so, look up
  164. ;;; the id in *id-to-objects*. 
  165. ;;; table. This will only happen if FORGET-REMOTE-TRANSLATION has been called
  166. ;;; on the local object.
  167.  
  168. (defun remote-object-value (remote)
  169.   "Return the associated value for the given remote object. It is an error if
  170.   the remote object was not created in this process or if
  171.   FORGET-REMOTE-TRANSLATION has been called on this remote object."
  172.   (declare (type remote-object remote))
  173.   (unless (remote-object-local-p remote)
  174.     (error "~S is defined is a different process." remote))
  175.   (multiple-value-bind
  176.       (value found)
  177.       (gethash (remote-object-id remote)
  178.            *id-to-object*)
  179.     (unless found
  180.       (cerror
  181.        "Use the value of NIL"
  182.        "No value for ~S -- FORGET-REMOTE-TRANSLATION was called to early."
  183.        remote))
  184.     value))
  185.  
  186. ;;; MAKE-REMOTE-OBJECT --- public
  187. ;;;
  188. ;;;   Convert the given local object to a remote object. If the local object is
  189. ;;; alread entered in the *object-to-id* hash table, just use the old id.
  190. ;;; Otherwise, grab the next id and put add both mappings to the two hash
  191. ;;; tables.
  192.  
  193. (defun make-remote-object (local)
  194.   "Convert the given local object to a remote object."
  195.   (unless *this-host*
  196.     (setf *this-host* (unix:unix-gethostid))
  197.     (setf *this-pid* (unix:unix-getpid)))
  198.   (let ((id (gethash local *object-to-id*)))
  199.     (unless id
  200.       (setf id *next-id*)
  201.       (setf (gethash local *object-to-id*) id)
  202.       (setf (gethash id *id-to-object*) local)
  203.       (incf *next-id*))
  204.     (%make-remote-object *this-host* *this-pid* id)))
  205.  
  206. ;;; FORGET-REMOTE-TRANSLATION -- public
  207. ;;;
  208. ;;;   Remove any translation information about the given object. If there is
  209. ;;; currenlt no translation for the object, don't bother doing anything.
  210. ;;; Otherwise remove it from the *object-to-id* hashtable, and remove the id
  211. ;;; from the *id-to-object* hashtable.
  212.  
  213. (defun forget-remote-translation (local)
  214.   "Forget the translation from the given local to the corresponding remote
  215. object. Passing that remote object to remote-object-value will new return NIL."
  216.   (let ((id (gethash local *object-to-id*)))
  217.     (when id
  218.       (remhash local *object-to-id*)
  219.       (remhash id *id-to-object*)))
  220.   (values))
  221.  
  222.  
  223. ;;; Wire input routeins.
  224.  
  225. ;;; WIRE-LISTEN -- public
  226. ;;;
  227. ;;;   If nothing is in the current input buffer, select on the file descriptor.
  228.  
  229. (defun wire-listen (wire)
  230.   "Return T iff anything is in the input buffer or available on the socket."
  231.   (or (< (wire-ibuf-offset wire)
  232.      (wire-ibuf-end wire))
  233.       (multiple-value-bind
  234.       (number error)
  235.       (unix:unix-select (1+ (wire-fd wire))
  236.                 (ash 1 (wire-fd wire))
  237.                 0
  238.                 0
  239.                 0)
  240.     (unless number
  241.       (error 'wire-io-error
  242.          :wire wire
  243.          :when "listening to"
  244.          :msg (unix:get-unix-error-msg error)))
  245.     (not (zerop number)))))
  246.  
  247.  
  248. ;;; FILL-INPUT-BUFFER -- Internal
  249. ;;;
  250. ;;;   Fill the input buffer from the socket. If we get an error reading, signal
  251. ;;; a wire-io-error. If we get an EOF, signal a wire-eof error. If we get any
  252. ;;; data, set the ibuf-end index.
  253.  
  254. (defun fill-input-buffer (wire)
  255.   "Read data off the socket, filling the input buffer. The buffer is cleared
  256. first. If fill-input-buffer returns, it is guarenteed that there will be at
  257. least one byte in the input buffer. If EOF was reached, as wire-eof error
  258. is signaled."
  259.   (setf (wire-ibuf-offset wire) 0
  260.     (wire-ibuf-end wire) 0)
  261.   (let ((fd (wire-fd wire))
  262.     (ibuf (wire-ibuf wire)))
  263.     (unless ibuf
  264.       (error 'wire-eof :wire wire))
  265.  
  266.     (multiple-value-bind
  267.     (bytes error)
  268.     (system:without-gcing
  269.      (unix:unix-read fd (system:vector-sap ibuf) buffer-size))
  270.       (cond ((null bytes)
  271.          (error 'wire-io-error
  272.             :wire wire
  273.             :when "reading"
  274.             :msg (unix:get-unix-error-msg error)))
  275.         ((zerop bytes)
  276.          (setf (wire-ibuf wire) nil)
  277.          (error 'wire-eof :wire wire))
  278.         (t
  279.          (setf (wire-ibuf-end wire) bytes)))))
  280.   (values))
  281.  
  282. ;;; WIRE-GET-BYTE -- public
  283. ;;;
  284. ;;;   Check to see if there is anything in the input buffer. If not, use
  285. ;;; FILL-INPUT-BUFFER to get something. Return the next byte, adjusting
  286. ;;; the input offset index.
  287.  
  288. (defun wire-get-byte (wire)
  289.   "Return the next byte from the wire."
  290.   (when (<= (wire-ibuf-end wire)
  291.         (wire-ibuf-offset wire))
  292.     (fill-input-buffer wire))
  293.   (prog1
  294.       (char-int (schar (wire-ibuf wire)
  295.                (wire-ibuf-offset wire)))
  296.     (incf (wire-ibuf-offset wire))))
  297.  
  298. ;;; WIRE-GET-NUMBER -- public
  299. ;;;
  300. ;;;   Just read four bytes and pack them together with normal math ops.
  301.  
  302. (defun wire-get-number (wire &optional (signed t))
  303.   "Read a number off the wire. Numbers are 4 bytes in network order.
  304. The optional argument controls weather or not the number should be considered
  305. signed (defaults to T)."
  306.   (let* ((b1 (wire-get-byte wire))
  307.      (b2 (wire-get-byte wire))
  308.      (b3 (wire-get-byte wire))
  309.      (b4 (wire-get-byte wire))
  310.      (unsigned
  311.       (+ b4 (* 256 (+ b3 (* 256 (+ b2 (* 256 b1))))))))
  312.     (if (and signed (> b1 127))
  313.     (logior (ash -1 32) unsigned)
  314.     unsigned)))
  315.  
  316. ;;; WIRE-GET-BIGNUM -- public
  317. ;;;
  318. ;;; Extracts a number, which might be a bignum.
  319. ;;;
  320. (defun wire-get-bignum (wire)
  321.   "Reads an arbitrary integer sent by WIRE-OUTPUT-BIGNUM from the wire and
  322.    return it."
  323.   (let ((count-and-sign (wire-get-number wire)))
  324.     (do ((count (abs count-and-sign) (1- count))
  325.      (result 0 (+ (ash result 32) (wire-get-number wire nil))))
  326.     ((not (plusp count))
  327.      (if (minusp count-and-sign)
  328.          (- result)
  329.          result)))))
  330.  
  331. ;;; WIRE-GET-STRING -- public
  332. ;;;
  333. ;;;   Use WIRE-GET-NUMBER to read the length, then keep pulling stuff out of
  334. ;;; the input buffer and re-filling it with FILL-INPUT-BUFFER until we've read
  335. ;;; the entire string.
  336.  
  337. (defun wire-get-string (wire)
  338.   "Reads a string from the wire. The first four bytes spec the size."
  339.   (let* ((length (wire-get-number wire))
  340.      (result (make-string length))
  341.      (offset 0)
  342.      (ibuf (wire-ibuf wire)))
  343.     (declare (simple-string result ibuf)
  344.          (integer length offset))
  345.     (loop
  346.       (let ((avail (- (wire-ibuf-end wire)
  347.               (wire-ibuf-offset wire))))
  348.     (declare (integer avail))
  349.     (cond ((<= length avail)
  350.            (replace result
  351.             ibuf
  352.             :start1 offset
  353.             :start2 (wire-ibuf-offset wire))
  354.            (incf (wire-ibuf-offset wire) length)
  355.            (return nil))
  356.           ((zerop avail)
  357.            (fill-input-buffer wire))
  358.           (t
  359.            (replace result
  360.             ibuf
  361.             :start1 offset
  362.             :start2 (wire-ibuf-offset wire)
  363.             :end2 (wire-ibuf-end wire))
  364.            (incf offset avail)
  365.            (decf length avail)
  366.            (incf (wire-ibuf-offset wire) avail)))))
  367.     result))
  368.     
  369. ;;; WIRE-GET-OBJECT -- public
  370. ;;;
  371. ;;;   First, read a byte to determine the type of the object to read. Then,
  372. ;;; depending on the type, call WIRE-GET-NUMBER, WIRE-GET-STRING, or whatever
  373. ;;; to read the necessary data. Note, funcall objects are funcalled.
  374.  
  375. (defun wire-get-object (wire)
  376.   "Reads the next object from the wire and returns it."
  377.   (let ((identifier (wire-get-byte wire))
  378.     (*current-wire* wire))
  379.     (declare (fixnum identifier))
  380.     (cond ((eql identifier lookup-op)
  381.        (let ((index (wire-get-number wire))
  382.          (cache (wire-object-cache wire)))
  383.          (declare (integer index))
  384.          (declare (simple-vector cache))
  385.          (when (< index (length cache))
  386.            (svref cache index))))
  387.       ((eql identifier number-op)
  388.        (wire-get-number wire))
  389.       ((eql identifier bignum-op)
  390.        (wire-get-bignum wire))
  391.       ((eql identifier string-op)
  392.        (wire-get-string wire))
  393.       ((eql identifier symbol-op)
  394.        (let* ((symbol-name (wire-get-string wire))
  395.           (package-name (wire-get-string wire))
  396.           (package (find-package package-name)))
  397.          (unless package
  398.            (error "Attempt to read symbol, ~A, of wire into non-existent ~
  399.                package, ~A."
  400.               symbol-name package-name))
  401.          (intern symbol-name package)))
  402.       ((eql identifier cons-op)
  403.        (cons (wire-get-object wire)
  404.          (wire-get-object wire)))
  405.       ((eql identifier remote-op)
  406.        (let ((host (wire-get-number wire nil))
  407.          (pid (wire-get-number wire))
  408.          (id (wire-get-number wire)))
  409.          (%make-remote-object host pid id)))
  410.       ((eql identifier save-op)
  411.        (let ((index (wire-get-number wire))
  412.          (cache (wire-object-cache wire)))
  413.          (declare (integer index))
  414.          (declare (simple-vector cache))
  415.          (when (>= index (length cache))
  416.            (do ((newsize (* (length cache) 2)
  417.                  (* newsize 2)))
  418.            ((< index newsize)
  419.             (let ((newcache (make-array newsize)))
  420.               (declare (simple-vector newcache))
  421.               (replace newcache cache)
  422.               (setf cache newcache)
  423.               (setf (wire-object-cache wire) cache)))))
  424.          (setf (svref cache index)
  425.            (wire-get-object wire))))
  426.       ((eql identifier funcall0-op)
  427.        (funcall (wire-get-object wire)))
  428.       ((eql identifier funcall1-op)
  429.        (funcall (wire-get-object wire)
  430.             (wire-get-object wire)))
  431.       ((eql identifier funcall2-op)
  432.        (funcall (wire-get-object wire)
  433.             (wire-get-object wire)
  434.             (wire-get-object wire)))
  435.       ((eql identifier funcall3-op)
  436.        (funcall (wire-get-object wire)
  437.             (wire-get-object wire)
  438.             (wire-get-object wire)
  439.             (wire-get-object wire)))
  440.       ((eql identifier funcall4-op)
  441.        (funcall (wire-get-object wire)
  442.             (wire-get-object wire)
  443.             (wire-get-object wire)
  444.             (wire-get-object wire)
  445.             (wire-get-object wire)))
  446.       ((eql identifier funcall5-op)
  447.        (funcall (wire-get-object wire)
  448.             (wire-get-object wire)
  449.             (wire-get-object wire)
  450.             (wire-get-object wire)
  451.             (wire-get-object wire)
  452.             (wire-get-object wire)))
  453.       ((eql identifier funcall-op)
  454.        (let ((arg-count (wire-get-byte wire))
  455.          (function (wire-get-object wire))
  456.          (args '())
  457.          (last-cons nil)
  458.          (this-cons nil))
  459.          (loop
  460.            (when (zerop arg-count)
  461.          (return nil))
  462.            (setf this-cons (cons (wire-get-object wire)
  463.                      nil))
  464.            (if (null last-cons)
  465.          (setf args this-cons)
  466.          (setf (cdr last-cons) this-cons))
  467.            (setf last-cons this-cons)
  468.            (decf arg-count))
  469.          (apply function args))))))
  470.  
  471.  
  472. ;;; Wire output routines.
  473.  
  474. ;;; WRITE-STUFF -- internal
  475. ;;;
  476. ;;;   Slightly better interface to unix:unix-write. Choaks on errors.
  477.  
  478. (defmacro write-stuff (fd string-form &optional end)
  479.   (let ((string (gensym))
  480.     (length (gensym))
  481.     (result (gensym))
  482.     (error (gensym)))
  483.     `(let* ((,string ,string-form)
  484.         ,@(unless end
  485.         `((,length (length ,string)))))
  486.        (multiple-value-bind
  487.        (,result ,error)
  488.        (unix:unix-write ,fd ,string 0 ,(or end length))
  489.      (cond ((null ,result)
  490.         (error 'wire-io-error
  491.                :wire wire
  492.                :when "writing"
  493.                :msg (unix:get-unix-error-msg ,error)))
  494.            ((eql ,result ,(or end length))
  495.         )
  496.            (t
  497.         (error 'wire-io-error
  498.                :wire wire
  499.                :when "writing"
  500.                :msg "Not everything wrote.")))))))
  501.  
  502. ;;; WIRE-FORCE-OUTPUT -- internal
  503. ;;;
  504. ;;;   Output any stuff remaining in the output buffer.
  505.  
  506. (defun wire-force-output (wire)
  507.   "Send any info still in the output buffer down the wire and clear it. Nothing
  508. harmfull will happen if called when the output buffer is empty."
  509.   (unless (zerop (wire-obuf-end wire))
  510.     (write-stuff (wire-fd wire)
  511.          (wire-obuf wire)
  512.          (wire-obuf-end wire))
  513.     (setf (wire-obuf-end wire) 0))
  514.   (values))
  515.  
  516. ;;; WIRE-OUTPUT-BYTE -- public
  517. ;;;
  518. ;;;   Stick the byte in the output buffer. If there is no space, flush the
  519. ;;; buffer using WIRE-FORCE-OUTPUT.
  520.  
  521. (defun wire-output-byte (wire byte)
  522.   "Output the given (8-bit) byte on the wire."
  523.   (declare (integer byte))
  524.   (let ((fill-pointer (wire-obuf-end wire))
  525.     (obuf (wire-obuf wire)))
  526.     (when (>= fill-pointer (length obuf))
  527.       (wire-force-output wire)
  528.       (setf fill-pointer 0))
  529.     (setf (schar obuf fill-pointer)
  530.       (code-char byte))
  531.     (setf (wire-obuf-end wire) (1+ fill-pointer)))
  532.   (values))
  533.  
  534. ;;; WIRE-OUTPUT-NUMBER -- public
  535. ;;;
  536. ;;;   Output the number. Note, we don't care if the number is signed or not,
  537. ;;; because we just crank out the low 32 bits.
  538. ;;;
  539. (defun wire-output-number (wire number)
  540.   "Output the given (32-bit) number on the wire."
  541.   (declare (integer number))
  542.   (wire-output-byte wire (+ 0 (ldb (byte 8 24) number)))
  543.   (wire-output-byte wire (ldb (byte 8 16) number))
  544.   (wire-output-byte wire (ldb (byte 8 8) number))
  545.   (wire-output-byte wire (ldb (byte 8 0) number))
  546.   (values))
  547.  
  548. ;;; WIRE-OUTPUT-BIGNUM -- public
  549. ;;;
  550. ;;; Output an arbitrary integer.
  551. ;;; 
  552. (defun wire-output-bignum (wire number)
  553.   "Outputs an arbitrary integer, but less effeciently than WIRE-OUTPUT-NUMBER."
  554.   (do ((digits 0 (1+ digits))
  555.        (remaining (abs number) (ash remaining -32))
  556.        (words nil (cons (ldb (byte 32 0) remaining) words)))
  557.       ((zerop remaining)
  558.        (wire-output-number wire
  559.                (if (minusp number)
  560.                    (- digits)
  561.                    digits))
  562.        (dolist (word words)
  563.      (wire-output-number wire word)))))
  564.  
  565. ;;; WIRE-OUTPUT-STRING -- public
  566. ;;;
  567. ;;;   Output the string. Strings are represented by the length as a number,
  568. ;;; followed by the bytes of the string.
  569. ;;;
  570. (defun wire-output-string (wire string)
  571.   "Output the given string. First output the length using WIRE-OUTPUT-NUMBER,
  572. then output the bytes."
  573.   (declare (simple-string string))
  574.   (let ((length (length string)))
  575.     (declare (integer length))
  576.     (wire-output-number wire length)
  577.     (let* ((obuf (wire-obuf wire))
  578.        (obuf-end (wire-obuf-end wire))
  579.        (available (- (length obuf)
  580.              obuf-end)))
  581.       (declare (simple-string obuf)
  582.            (integer available))
  583.       (cond ((>= available length)
  584.          (replace obuf string
  585.               :start1 obuf-end)
  586.          (incf (wire-obuf-end wire) length))
  587.         ((> length (length obuf))
  588.          (wire-force-output wire)
  589.          (write-stuff (wire-fd wire)
  590.               string))
  591.         (t
  592.          (wire-force-output wire)
  593.          (replace obuf string)
  594.          (setf (wire-obuf-end wire) length)))))
  595.   (values))
  596.  
  597. ;;; WIRE-OUTPUT-OBJECT -- public
  598. ;;;
  599. ;;;   Output the given object. If the optional argument is non-nil, cache
  600. ;;; the object to enhance the performance of sending it multiple times.
  601. ;;; Caching defaults to yes for symbols, and nil for everything else.
  602.  
  603. (defun wire-output-object (wire object &optional (cache-it (symbolp object)))
  604.   "Output the given object on the given wire. If cache-it is T, enter this
  605. object in the cache for future reference."
  606.   (let ((cache-index (gethash object
  607.                   (wire-object-hash wire))))
  608.     (cond
  609.      (cache-index
  610.       (wire-output-byte wire lookup-op)
  611.       (wire-output-number wire cache-index))
  612.      (t
  613.       (when cache-it
  614.     (wire-output-byte wire save-op)
  615.     (let ((index (wire-cache-index wire)))
  616.       (wire-output-number wire index)
  617.       (setf (gethash object (wire-object-hash wire))
  618.         index)
  619.       (setf (wire-cache-index wire) (1+ index))))
  620.       (typecase object
  621.     (integer
  622.      (cond ((typep object '(signed-byte 32))
  623.         (wire-output-byte wire number-op)
  624.         (wire-output-number wire object))
  625.            (t
  626.         (wire-output-byte wire bignum-op)
  627.         (wire-output-bignum wire object))))
  628.     (simple-string
  629.      (wire-output-byte wire string-op)
  630.      (wire-output-string wire object))
  631.     (symbol
  632.      (wire-output-byte wire symbol-op)
  633.      (wire-output-string wire (symbol-name object))
  634.      (wire-output-string wire (package-name (symbol-package object))))
  635.     (cons
  636.      (wire-output-byte wire cons-op)
  637.      (wire-output-object wire (car object))
  638.      (wire-output-object wire (cdr object)))
  639.     (remote-object
  640.      (wire-output-byte wire remote-op)
  641.      (wire-output-number wire (remote-object-host object))
  642.      (wire-output-number wire (remote-object-pid object))
  643.      (wire-output-number wire (remote-object-id object)))
  644.     (t
  645.      (error "Error: Cannot output objects of type ~s across a wire."
  646.         (type-of object)))))))
  647.   (values))
  648.  
  649. ;;; WIRE-OUTPUT-FUNCALL -- public
  650. ;;;
  651. ;;;   Send the funcall down the wire. Arguments are evaluated locally in the
  652. ;;; lexical environment of the WIRE-OUTPUT-FUNCALL.
  653.  
  654. (defmacro wire-output-funcall (wire-form function &rest args)
  655.   "Send the function and args down the wire as a funcall."
  656.   (let ((num-args (length args))
  657.     (wire (gensym)))
  658.     `(let ((,wire ,wire-form))
  659.        ,@(if (> num-args 5)
  660.         `((wire-output-byte ,wire funcall-op)
  661.           (wire-output-byte ,wire ,num-args))
  662.         `((wire-output-byte ,wire ,(+ funcall0-op num-args))))
  663.        (wire-output-object ,wire ,function)
  664.        ,@(mapcar #'(lambda (arg)
  665.              `(wire-output-object ,wire ,arg))
  666.          args)
  667.        (values))))
  668.  
  669.